package top.kangyaocoding.ecommerce.impl;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.chat.MessageFormat;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.Media;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import top.kangyaocoding.ecommerce.IChatAIService;
import top.kangyaocoding.ecommerce.constants.Constants;
import top.kangyaocoding.ecommerce.dao.IAiResponsesDao;
import top.kangyaocoding.ecommerce.dto.ChatAiDTO;
import top.kangyaocoding.ecommerce.exception.AppException;
import top.kangyaocoding.ecommerce.po.AiResponses;
import top.kangyaocoding.ecommerce.req.ChatAiReq;
import top.kangyaocoding.ecommerce.response.Response;
import top.kangyaocoding.ecommerce.utils.JwtUtil;
import top.kangyaocoding.ecommerce.vo.UserRoleVO;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;

/**
 * 描述: AI 聊天服务实现类
 *
 * @author K·Herbert
 * @since 2025-04-05 16:05
 */
@Slf4j
@Service
public class ChatAIService implements IChatAIService {

    private Resource currentImageResource;

    private static final String IMAGE_NAME = "main.png";
    private static final String UPLOAD_DIR = "./uploads/";
    public static final String MODEL = "qwen-omni-turbo-latest";

    private final JwtUtil jwtUtil;
    private final DashScopeChatModel dashScopeChatClient;
    private final IAiResponsesDao aiResponsesDao;

    public ChatAIService(JwtUtil jwtUtil, DashScopeChatModel dashScopeChatClient, IAiResponsesDao aiResponsesDao) {
        this.jwtUtil = jwtUtil;
        this.dashScopeChatClient = dashScopeChatClient;
        this.aiResponsesDao = aiResponsesDao;
        initializeImageResource();
    }

    private void initializeImageResource() {
        try {
            // 确保上传目录存在
            Files.createDirectories(Paths.get(UPLOAD_DIR));

            Path imagePath = Paths.get(UPLOAD_DIR, IMAGE_NAME);
            if (Files.exists(imagePath)) {
                currentImageResource = new FileSystemResource(imagePath.toFile());
                log.info("Using existing image from uploads directory");
            } else {
                log.warn("No image found in uploads directory");
                currentImageResource = null;
            }
        } catch (Exception e) {
            log.error("Failed to initialize image resource", e);
            currentImageResource = null;
        }
    }

    @Override
    public Response<List<ChatAiDTO>> findAll(String token) {
        // 获取角色
        String role = jwtUtil.getRoleFromToken(token);
        if (!role.equals(UserRoleVO.DECISION_MAKER.getCode())) {
            return Response.<List<ChatAiDTO>>builder()
                    .code(Constants.ErrorCode.UNAUTHORIZED.getCode())
                    .info(Constants.ErrorCode.UNAUTHORIZED.getInfo())
                    .data(null)
                    .build();
        }

        List<AiResponses> aiResponsesDaoAll = aiResponsesDao.findAll();
        if (null == aiResponsesDaoAll || aiResponsesDaoAll.isEmpty()) {
            return Response.<List<ChatAiDTO>>builder()
                    .code(Constants.ErrorCode.SUCCESS.getCode())
                    .info(Constants.ErrorCode.SUCCESS.getInfo())
                    .data(null)
                    .build();
        }
        List<ChatAiDTO> chatAiDTOS = aiResponsesDaoAll.stream()
                .map(aiResponses -> ChatAiDTO.builder()
                        .id(aiResponses.getId())
                        .userId(aiResponses.getUserId())
                        .sessionId(aiResponses.getSessionId())
                        .requestText(aiResponses.getRequestText())
                        .responseText(aiResponses.getResponseText())
                        .createdAt(aiResponses.getCreatedAt())
                        .build())
                .toList();
        log.info("获取AI智能建议记录成功！");
        return Response.<List<ChatAiDTO>>builder()
                .code(Constants.ErrorCode.SUCCESS.getCode())
                .info(Constants.ErrorCode.SUCCESS.getInfo())
                .data(chatAiDTOS)
                .build();
    }

    @Override
    public Response<String> uploadImage(MultipartFile file, String token) {
        // 从Token中获取角色
        String role = jwtUtil.getRoleFromToken(token);
        if (!role.equals(UserRoleVO.DECISION_MAKER.getCode())) {
            return Response.<String>builder()
                    .code(Constants.ErrorCode.UNAUTHORIZED.getCode())
                    .info(Constants.ErrorCode.UNAUTHORIZED.getInfo())
                    .data("无权限").build();
        }
        if (file.isEmpty()) {
            return Response.<String>builder()
                    .code(Constants.ErrorCode.ILLEGAL_PARAMETER.getCode())
                    .info(Constants.ErrorCode.ILLEGAL_PARAMETER.getInfo())
                    .data("请选择要上传的文件").build();
        }
        try {
            // 确保上传目录存在
            Files.createDirectories(Paths.get(UPLOAD_DIR));
            // 保存文件（自动覆盖已存在的文件）
            Path targetLocation = Paths.get(UPLOAD_DIR, IMAGE_NAME);
            try (InputStream inputStream = file.getInputStream()) {
                Files.copy(inputStream, targetLocation, StandardCopyOption.REPLACE_EXISTING);
            }
            // 更新当前图片资源
            currentImageResource = new FileSystemResource(targetLocation.toFile());
            log.info("已成功将图像上传到： {}", targetLocation);
            return Response.<String>builder()
                    .code(Constants.ErrorCode.SUCCESS.getCode())
                    .info(Constants.ErrorCode.SUCCESS.getInfo())
                    .data("图片上传成功").build();
        } catch (IOException e) {
            log.error("Failed to upload image", e);
            throw new AppException(
                    Constants.ErrorCode.UN_ERROR.getCode(),
                    Constants.ErrorCode.UN_ERROR.getInfo()
            );
        }
    }

    @Override
    public Flux<AssistantMessage> streamImage(ChatAiReq request, String token) {
        // 从Token中获取角色
        String role = jwtUtil.getRoleFromToken(token);
        if (!role.equals(UserRoleVO.DECISION_MAKER.getCode())) {
            // UNAUTHORIZED
            return Flux.error(new AppException(
                    Constants.ErrorCode.UNAUTHORIZED.getCode(),
                    Constants.ErrorCode.UNAUTHORIZED.getInfo()
            ));
        }
        // 参数校验
        if (currentImageResource == null || !currentImageResource.exists()) {
            log.error("参数错误: {}", Constants.ErrorCode.ILLEGAL_PARAMETER.getCode());
            return Flux.error(new AppException(
                    Constants.ErrorCode.ILLEGAL_PARAMETER.getCode(),
                    Constants.ErrorCode.ILLEGAL_PARAMETER.getInfo())
            );
        }
        // 从Token中获取用户id
        Long userId = jwtUtil.getUserIdFromToken(token);
        // 初始化数据库记录
        AiResponses aiResponses = new AiResponses();
        aiResponses.setUserId(userId);
        aiResponses.setSessionId(request.getSessionId());
//        aiResponses.setModelName(request.getModelName());
        aiResponses.setModelName(MODEL);
        aiResponses.setRequestText(request.getRequestText());
        aiResponses.setStatus(1); // 默认成功状态

        try {
            List<Media> mediaList = List.of(
                    new Media(MimeTypeUtils.IMAGE_PNG, currentImageResource));
            // 使用智能建议模板
            String prompt = Constants.SUGGESTION_TEMPLATE;
            UserMessage message = new UserMessage(prompt, mediaList);
            message.getMetadata().put(DashScopeChatModel.MESSAGE_FORMAT, MessageFormat.IMAGE);
            Flux<ChatResponse> result = dashScopeChatClient.stream(
                    new Prompt(message, DashScopeChatOptions.builder()
                                    .withTemperature(0.8)
                                    .withModel(MODEL)
                                    .withMultiModel(true)
                                    .withIncrementalOutput(true)
                                    .withStream(true)
                                    .build()));
            // 使用StringBuilder替代字符串拼接
            StringBuilder contentBuilder = new StringBuilder();
            return result
                    // 1. 处理流数据
                    .map(chatResponse -> {
                        // 累积响应内容
                        String deltaContent = chatResponse.getResult().getOutput().getContent();
                        contentBuilder.append(deltaContent);
                        // 检查是否是最终响应
                        if ("STOP".equals(chatResponse.getResult().getMetadata()
                                .getFinishReason())) {
                            aiResponses.setPromptTokens(chatResponse.getMetadata().getUsage()
                                    .getPromptTokens());
                            aiResponses.setCompletionTokens(chatResponse.getMetadata().getUsage()
                                    .getGenerationTokens());
                            aiResponses.setTotalTokens(chatResponse.getMetadata().getUsage()
                                    .getTotalTokens());
                            log.info("Tokens used - prompt: {}, completion: {}, total: {}",
                                    aiResponses.getPromptTokens(),
                                    aiResponses.getCompletionTokens(),
                                    aiResponses.getTotalTokens());
                        }
                        return chatResponse.getResult().getOutput();
                    })
                    // 2. 流结束后保存数据
                    .doOnComplete(() -> {
                        aiResponses.setResponseText(contentBuilder.toString());
                        aiResponses.setStatus(1); // 明确设置为成功
                        try {
                            aiResponsesDao.insert(aiResponses);
                        } catch (Exception e) {
                            log.error("保存数据时发生错误", e);
                            throw new RuntimeException(e);
                        }
                    })
                    // 3. 错误处理
                    .onErrorResume(e -> {
                        log.error("处理流时发生错误", e);
                        aiResponses.setStatus(0);
                        aiResponses.setErrorMessage(e.getMessage());
                        aiResponses.setResponseText(contentBuilder.toString());

                        try {
                            aiResponsesDao.insert(aiResponses);
                        } catch (Exception ex) {
                            log.error("保存数据时发生错误", ex);
                            throw new RuntimeException(ex);
                        }

                        return Flux.error(new AppException(
                                Constants.ErrorCode.UN_ERROR.getCode(),
                                Constants.ErrorCode.UN_ERROR.getInfo(),
                                e
                        ));
                    });
        } catch (Exception e) {
            log.error("初始化text-to-image失败", e);
            aiResponses.setStatus(1);
            aiResponses.setErrorMessage(e.getMessage());
            try {
                aiResponsesDao.insert(aiResponses);
            } catch (Exception ex) {
                log.error("保存数据时发生错误", ex);
                throw new RuntimeException(ex);
            }

            return Flux.error(new AppException(
                    Constants.ErrorCode.UN_ERROR.getCode(),
                    Constants.ErrorCode.UN_ERROR.getInfo(),
                    e
            ));
        }
    }
}
